/** 
 * @Description: Cesium导航信息显示类，用于显示比例尺、经纬度、高度等信息
 * @Author: 程前
 * @Date: 2024-12-06 14:29:28
 * @LastEditors: 程前
 * @LastEditTime: 2024-12-11 17:08:07
 */
import {
    Viewer,
    Cartographic,
    Math as CesiumMath,
    ScreenSpaceEventHandler,
    ScreenSpaceEventType,
    EllipsoidGeodesic,
    Cartesian2
} from 'cesium';
import { setEventByHandler, removeEventByHandler, eventBus, throttle } from '@/utils';
/**
 * Cesium导航信息显示类
 */
export default class CesiumBarInfo {
    private viewer: Viewer;
    private handler: ScreenSpaceEventHandler;
    private lastMouseInfo: any = null;
    private updateThrottled: Function;
    private lastPosition: any = null;
    private throttleTime: number = 0;

    /**
     * 构造函数
     * @param viewer Cesium实例
     */
    constructor(viewer: Viewer, throttleTime?: number) {
        this.viewer = viewer;
        this.throttleTime = throttleTime || 100;
        this.handler = new ScreenSpaceEventHandler(this.viewer.scene.canvas);
        this.updateThrottled = throttle((position?: any) => {
            this.updateInfo(position);
        }, this.throttleTime);
        this.initEventListeners();
    }

    /**
     * 初始化事件监听
     */
    private initEventListeners(): void {
        const mouseMove = (movement: any) => {
            this.lastPosition = movement.endPosition;
            this.updateThrottled(movement.endPosition);
        }
        setEventByHandler(this.handler, mouseMove, ScreenSpaceEventType.MOUSE_MOVE);
        this.viewer.camera.changed.addEventListener(() => {
            this.updateThrottled(this.lastPosition);
        });
    }

    /**
     * 更新显示信息
     * @param position 鼠标位置
     */
    private updateInfo(position?: any): void {
        const scene = this.viewer.scene;
        const camera = this.viewer.camera;

        // 获取相机高度
        const cameraHeight = Math.round(camera.positionCartographic.height);

        // 计算比例尺（无论是否有鼠标位置都计算）
        let metersPerCm = 0;
        const width = scene.canvas.clientWidth;
        const height = scene.canvas.clientHeight;
        const left = scene.camera.pickEllipsoid(
            new Cartesian2(0, height / 2),
            scene.globe.ellipsoid
        );
        const right = scene.camera.pickEllipsoid(
            new Cartesian2(width, height / 2),
            scene.globe.ellipsoid
        );

        if (left && right) {
            const geodesic = new EllipsoidGeodesic(
                Cartographic.fromCartesian(left),
                Cartographic.fromCartesian(right)
            );
            const distance = geodesic.surfaceDistance;
            const scaleWidth = 100;
            metersPerCm = (distance / width) * scaleWidth;
        }

        let mouseInfo: any = {
            longitude: '',
            latitude: '',
            height: 0,
            cameraHeight,
            metersPerCm
        };
        //优化为有地形图时才计算高度
        // if (scene.terrainProvider) {
        //     const ray = scene.camera.getPickRay(position);
        //     if (ray) {
        //         const cartesianPosition = scene.globe.pick(ray, scene);
        //         if (cartesianPosition) {
        //             const terrainCartographic = Cartographic.fromCartesian(cartesianPosition);
        //             mouseInfo.height = Math.round(terrainCartographic.height);
        //         }
        //     }
        // }
        if (position) {
            const windowPosition = new Cartesian2(position.x, position.y);
            const cartesian = scene.globe.pick(scene.camera.getPickRay(windowPosition), scene);
            if (cartesian) {
                const cartographic = scene.globe.ellipsoid.cartesianToCartographic(cartesian);
                if (cartographic) {
                    // 转换为度数
                    const longitudeDegrees = CesiumMath.toDegrees(cartographic.longitude);
                    const latitudeDegrees = CesiumMath.toDegrees(cartographic.latitude);
                    mouseInfo.longitude = longitudeDegrees.toFixed(5);
                    mouseInfo.latitude = latitudeDegrees.toFixed(5);

                    if (scene.terrainProvider) {
                        // mouseInfo.height = Math.round(cartographic.height) < 0 ? 0 : Math.round(cartographic.height);
                        mouseInfo.height = Math.round(cartographic.height)
                    }
                }
            }
        }

        // 检查数据是否有变化
        if (JSON.stringify(this.lastMouseInfo) !== JSON.stringify(mouseInfo)) {
            this.lastMouseInfo = mouseInfo;
            eventBus.emit('cesiumBarInfo', mouseInfo);
        }
    }

    /**
     * 销毁实例，清理资源
     */
    destroy(): void {
        if (this.handler) {
            this.handler.destroy();
        }
    }
} 